home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / readline.lha / readline / vi_mode.c < prev   
C/C++ Source or Header  |  1991-04-25  |  18KB  |  988 lines

  1. /* vi_mode.c -- A vi emulation mode for Bash.
  2.  
  3.    Derived from code written by Jeff Sparkes (jeff1@????).
  4.  */
  5.  
  6.  
  7. /* **************************************************************** */
  8. /*                                    */
  9. /*            VI Emulation Mode                */
  10. /*                                    */
  11. /* **************************************************************** */
  12.  
  13. /* Last string searched for from `/' or `?'. */
  14. static char *vi_last_search = (char *)NULL;
  15. static int vi_histpos;
  16.  
  17. /* Non-zero means enter insertion mode. */
  18. int vi_doing_insert = 0;
  19.  
  20. /* *** UNCLEAN *** */
  21. /* Command keys which do movement for xxx_to commands. */
  22. static char *vi_motion = " hl^$0ftFt;,%wbeWBE|";
  23.  
  24. /* Keymap used for vi replace characters.  Created dynamically since
  25.    rarely used. */
  26. static Keymap vi_replace_map = (Keymap)NULL;
  27.  
  28. /* The number of characters inserted in the last replace operation. */
  29. static vi_replace_count = 0;
  30.  
  31. /* Yank the nth arg from the previous line into this line at point. */
  32. rl_vi_yank_arg (count)
  33.      int count;
  34. {
  35.   rl_yank_nth_arg (count, 0);
  36. }
  37.  
  38. /* Search again for the last thing searched for. */
  39. rl_vi_search_again (ignore, key)
  40.      int ignore, key;
  41. {
  42.   switch (key)
  43.     {
  44.     case 'n':
  45.       rl_vi_dosearch (vi_last_search, -1);
  46.       break;
  47.  
  48.     case 'N':
  49.       rl_vi_dosearch (vi_last_search, 1);
  50.       break;
  51.     }
  52. }
  53.  
  54. /* Do a vi style search. */
  55. rl_vi_search (count, key)
  56.      int count, key;
  57. {
  58.   int dir, c, save_pos;
  59.   char *p;
  60.  
  61.   switch (key)
  62.     {
  63.     case '?':
  64.       dir = 1;
  65.       break;
  66.  
  67.     case '/':
  68.       dir = -1;
  69.       break;
  70.  
  71.     default:
  72.       ding ();
  73.       return;
  74.     }
  75.  
  76.   vi_histpos = where_history ();
  77.   maybe_save_line ();
  78.   save_pos = rl_point;
  79.  
  80.   /* Reuse the line input buffer to read the search string. */
  81.   the_line[0] = 0;
  82.   rl_end = rl_point = 0;
  83.   p = (char *)alloca (2 + (rl_prompt ? strlen (rl_prompt) : 0));
  84.  
  85.   sprintf (p, "%s%c", rl_prompt ? rl_prompt : "", key);
  86.  
  87.   rl_message (p, 0, 0);
  88.  
  89.   while (c = rl_read_key ())
  90.     {
  91.       switch (c)
  92.     {
  93.     case CTRL('H'):
  94.     case RUBOUT:
  95.       if (rl_point == 0)
  96.         {
  97.           maybe_unsave_line ();
  98.           rl_clear_message ();
  99.           rl_point = save_pos;
  100.           return;
  101.         }
  102.  
  103.     case CTRL('W'):
  104.     case CTRL('U'):
  105.       rl_dispatch (c, keymap);
  106.       break;
  107.  
  108.     case ESC:
  109.     case RETURN:
  110.     case NEWLINE:
  111.       goto dosearch;
  112.       break;
  113.  
  114.     case CTRL('C'):
  115.       maybe_unsave_line ();
  116.       rl_clear_message ();
  117.       rl_point = 0;
  118.       ding ();
  119.       return;
  120.  
  121.     default:
  122.       rl_insert (1, c);
  123.       break;
  124.     }
  125.       rl_redisplay ();
  126.     }
  127.  dosearch:
  128.   if (vi_last_search)
  129.     free (vi_last_search);
  130.  
  131.   vi_last_search = savestring (the_line);
  132.   rl_vi_dosearch (the_line, dir);
  133. }
  134.  
  135. rl_vi_dosearch (string, dir)
  136.      char *string;
  137.      int dir;
  138. {
  139.   int old, save = vi_histpos;
  140.   HIST_ENTRY *h;
  141.  
  142.   if (string == 0 || *string == 0 || vi_histpos < 0)
  143.     {
  144.       ding ();
  145.       return;
  146.     }
  147.  
  148.   if ((save = history_search_pos (string, dir, vi_histpos + dir)) == -1)
  149.     {
  150.       maybe_unsave_line ();
  151.       rl_clear_message ();
  152.       rl_point = 0;
  153.       ding ();
  154.       return;
  155.     }
  156.  
  157.   vi_histpos = save;
  158.  
  159.   old = where_history ();
  160.   history_set_pos (vi_histpos);
  161.   h = current_history ();
  162.   history_set_pos (old);
  163.  
  164.   strcpy (the_line, h->line);
  165.   rl_undo_list = (UNDO_LIST *)h->data;
  166.   rl_end = strlen (the_line);
  167.   rl_point = 0;
  168.   rl_clear_message ();
  169. }
  170.  
  171. /* Completion, from vi's point of view. */
  172. rl_vi_complete (ignore, key)
  173.      int ignore, key;
  174. {
  175.   if ((rl_point < rl_end) && (!whitespace (the_line[rl_point])))
  176.     {
  177.       if (!whitespace (the_line[rl_point + 1]))
  178.     rl_vi_end_word (1, 'E');
  179.       rl_point++;
  180.     }
  181.  
  182.   if (key == '*')
  183.     rl_complete_internal ('*');
  184.   else
  185.     rl_complete (0, key);
  186.  
  187.   rl_vi_insertion_mode ();
  188. }
  189.  
  190. /* Previous word in vi mode. */
  191. rl_vi_prev_word (count, key)
  192.      int count, key;
  193. {
  194.   if (count < 0)
  195.     {
  196.       rl_vi_next_word (-count, key);
  197.       return;
  198.     }
  199.  
  200.   if (uppercase_p (key))
  201.     rl_vi_bWord (count);
  202.   else
  203.     rl_vi_bword (count);
  204. }
  205.  
  206. /* Next word in vi mode. */
  207. rl_vi_next_word (count, key)
  208.      int count;
  209. {
  210.   if (count < 0)
  211.     {
  212.       rl_vi_prev_word (-count, key);
  213.       return;
  214.     }
  215.  
  216.   if (uppercase_p (key))
  217.     rl_vi_fWord (count);
  218.   else
  219.     rl_vi_fword (count);
  220. }
  221.  
  222. /* Move to the end of the ?next? word. */
  223. rl_vi_end_word (count, key)
  224.      int count, key;
  225. {
  226.   if (count < 0)
  227.     {
  228.       ding ();
  229.       return;
  230.     }
  231.  
  232.   if (uppercase_p (key))
  233.     rl_vi_eWord (count);
  234.   else
  235.     rl_vi_eword (count);
  236. }
  237.  
  238. /* Move forward a word the way that 'W' does. */
  239. /* Move forward a word the way that 'W' does. */
  240. rl_vi_fWord (count)
  241.      int count;
  242. {
  243.   while (count-- && rl_point < (rl_end - 1))
  244.     {
  245.       /* Skip until whitespace. */
  246.       while (!whitespace (the_line[rl_point]) && rl_point < rl_end)
  247.         rl_point++;
  248.  
  249.       /* Now skip whitespace. */
  250.       while (whitespace (the_line[rl_point]) && rl_point < rl_end)
  251.         rl_point++;
  252.     }
  253. }
  254.  
  255. rl_vi_bWord (count)
  256.      int count;
  257. {
  258.   while (count-- && rl_point > 0)
  259.     {
  260.       /* If we are at the start of a word, move back to whitespace so
  261.          we will go back to the start of the previous word. */
  262.       if (!whitespace (the_line[rl_point]) &&
  263.           whitespace (the_line[rl_point - 1]))
  264.         rl_point--;
  265.  
  266.       while (rl_point > 0 && whitespace (the_line[rl_point]))
  267.         rl_point--;
  268.  
  269.       if (rl_point > 0)
  270.         {
  271.           while (--rl_point >= 0 && !whitespace (the_line[rl_point]));
  272.           rl_point++;
  273.         }
  274.     }
  275. }
  276.  
  277. rl_vi_eWord (count)
  278.      int count;
  279. {
  280.   while (count-- && rl_point < (rl_end - 1))
  281.     {
  282.       /* Move to white space. */
  283.       while (++rl_point < rl_end && whitespace (the_line[rl_point]))
  284.         ;
  285.  
  286.       if (rl_point && rl_point < rl_end)
  287.         {
  288.           /* Skip whitespace. */
  289.           while (rl_point < rl_end && whitespace (the_line[rl_point]))
  290.             rl_point++;
  291.  
  292.           /* Skip until whitespace. */
  293.           while (rl_point < rl_end && !whitespace (the_line[rl_point]))
  294.             rl_point++;
  295.  
  296.           /* Move back to the last character of the word. */
  297.           rl_point--;
  298.         }
  299.     }
  300. }
  301.  
  302. rl_vi_fword (count)
  303.      int count;
  304. {
  305.   while (count-- && rl_point < (rl_end - 1))
  306.     {
  307.       /* Move to white space (really non-identifer). */
  308.       if (isident (the_line[rl_point]))
  309.         {
  310.           while (isident (the_line[rl_point]) && rl_point < rl_end)
  311.             rl_point++;
  312.         }
  313.       else /* if (!whitespace (the_line[rl_point])) */
  314.         {
  315.           while (!isident (the_line[rl_point]) &&
  316.                  !whitespace (the_line[rl_point]) && rl_point < rl_end)
  317.             rl_point++;
  318.         }
  319.  
  320.       /* Move past whitespace. */
  321.       while (whitespace (the_line[rl_point]) && rl_point < rl_end)
  322.         rl_point++;
  323.     }
  324. }
  325.  
  326. rl_vi_bword (count)
  327.      int count;
  328. {
  329.   while (count-- && rl_point > 0)
  330.     {
  331.       int last_is_ident;
  332.  
  333.       /* If we are at the start of a word, move back to a non-identifier
  334.          so we will go back to the start of the previous word. */
  335.       if (isident (the_line[rl_point]) && !isident (the_line[rl_point - 1]))
  336.         rl_point--;
  337.  
  338.       /* If this character and the previous character are `opposite', move
  339.          back so we don't get messed up by the rl_point++ down there in
  340.          the while loop.  Without this code, words like `l;' screw up the
  341.          function. */
  342.       last_is_ident = isident (the_line[rl_point - 1]);
  343.       if ((isident (the_line[rl_point]) && !last_is_ident) ||
  344.           (!isident (the_line[rl_point]) && last_is_ident))
  345.         rl_point--;
  346.  
  347.       while (rl_point > 0 && whitespace (the_line[rl_point]))
  348.         rl_point--;
  349.  
  350.       if (rl_point > 0)
  351.         {
  352.           if (isident (the_line[rl_point]))
  353.             while (--rl_point >= 0 && isident (the_line[rl_point]));
  354.           else
  355.             while (--rl_point >= 0 && !isident (the_line[rl_point]) &&
  356.                    !whitespace (the_line[rl_point]));
  357.           rl_point++;
  358.         }
  359.     }
  360. }
  361.  
  362. rl_vi_eword (count)
  363.      int count;
  364. {
  365.   while (count-- && rl_point < rl_end - 1)
  366.     {
  367.       while (++rl_point < rl_end && whitespace (the_line[rl_point]))
  368.         ;
  369.  
  370.       if (rl_point < rl_end)
  371.         {
  372.           if (isident (the_line[rl_point]))
  373.             while (++rl_point < rl_end && isident (the_line[rl_point]));
  374.           else
  375.             while (++rl_point < rl_end && !isident (the_line[rl_point])
  376.                    && !whitespace (the_line[rl_point]));
  377.           rl_point--;
  378.         }
  379.     }
  380. }
  381.  
  382. rl_vi_insert_beg ()
  383. {
  384.   rl_beg_of_line ();
  385.   rl_vi_insertion_mode ();
  386.   return 0;
  387. }
  388.  
  389. rl_vi_append_mode ()
  390. {
  391.   if (rl_point < rl_end)
  392.     rl_point += 1;
  393.   rl_vi_insertion_mode ();
  394.   return 0;
  395. }
  396.  
  397. rl_vi_append_eol ()
  398. {
  399.   rl_end_of_line ();
  400.   rl_vi_append_mode ();
  401.   return 0;
  402. }
  403.  
  404. /* What to do in the case of C-d. */
  405. rl_vi_eof_maybe (count, c)
  406.      int count, c;
  407. {
  408.   rl_newline (1, '\n');
  409. }
  410.  
  411. /* Insertion mode stuff. */
  412.  
  413. /* Switching from one mode to the other really just involves
  414.    switching keymaps. */
  415. rl_vi_insertion_mode ()
  416. {
  417.   keymap = vi_insertion_keymap;
  418. }
  419.  
  420. rl_vi_movement_mode ()
  421. {
  422.   if (rl_point > 0)
  423.     rl_backward (1);
  424.  
  425.   keymap = vi_movement_keymap;
  426.   vi_done_inserting ();
  427. }
  428.  
  429. vi_done_inserting ()
  430. {
  431.   if (vi_doing_insert)
  432.     {
  433.       rl_end_undo_group ();
  434.       vi_doing_insert = 0;
  435.     }
  436. }
  437.  
  438. rl_vi_arg_digit (count, c)
  439.      int count, c;
  440. {
  441.   if (c == '0' && rl_numeric_arg == 1 && !rl_explicit_arg)
  442.     rl_beg_of_line ();
  443.   else
  444.     rl_digit_argument (count, c);
  445. }
  446.  
  447. /* Doesn't take an arg count in vi */
  448. rl_vi_change_case (ignore1, ignore2)
  449.      int ignore1, ignore2;
  450. {
  451.   char c = 0;
  452.  
  453.   /* Don't try this on an empty line. */
  454.   if (rl_point >= rl_end - 1)
  455.     return;
  456.  
  457.   if (uppercase_p (the_line[rl_point]))
  458.     c = to_lower (the_line[rl_point]);
  459.   else if (lowercase_p (the_line[rl_point]))
  460.     c = to_upper (the_line[rl_point]);
  461.  
  462.   /* Vi is kind of strange here. */
  463.   if (c)
  464.     {
  465.       rl_begin_undo_group ();
  466.       rl_delete (1, c);
  467.       rl_insert (1, c);
  468.       rl_end_undo_group ();
  469.       rl_vi_check ();
  470.     }
  471.   else
  472.     rl_forward (1);
  473. }
  474.  
  475. rl_vi_put (count, key)
  476.      int count, key;
  477. {
  478.   if (!uppercase_p (key) && (rl_point + 1 <= rl_end))
  479.     rl_forward (1);
  480.  
  481.   rl_yank ();
  482.   rl_backward (1);
  483. }
  484.  
  485. rl_vi_check ()
  486. {
  487.   if (rl_point && rl_point == rl_end)
  488.     rl_point--;
  489. }
  490.  
  491. rl_vi_column (count)
  492. {
  493.   if (count > rl_end)
  494.     rl_end_of_line ();
  495.   else
  496.     rl_point = count - 1;
  497. }
  498.  
  499. int
  500. rl_vi_domove (key, nextkey)
  501.      int key, *nextkey;
  502. {
  503.   int c, save;
  504.  
  505.   rl_mark = rl_point;
  506.   c = rl_read_key ();
  507.   *nextkey = c;
  508.  
  509.   if (!member (c, vi_motion))
  510.     {
  511.       if (digit (c))
  512.     {
  513.       save = rl_numeric_arg;
  514.       rl_digit_loop1 ();
  515.       rl_numeric_arg *= save;
  516.     }
  517.       else if ((key == 'd' && c == 'd') ||
  518.            (key == 'c' && c == 'c'))
  519.     {
  520.       rl_mark = rl_end;
  521.       rl_beg_of_line ();
  522.       return (0);
  523.     }
  524.       else
  525.     return (-1);
  526.     }
  527.  
  528.   rl_dispatch (c, keymap);
  529.  
  530.   /* No change in position means the command failed. */
  531.   if (rl_mark == rl_point)
  532.     return (-1);
  533.  
  534.   if ((c == 'w' || c == 'W') && rl_point < rl_end)
  535.     rl_point--;
  536.  
  537.   if (rl_mark < rl_point)
  538.     exchange (rl_point, rl_mark);
  539.  
  540.   return (0);
  541. }
  542.  
  543. /* A simplified loop for vi. Don't dispatch key at end.
  544.    Don't recognize minus sign? */
  545. rl_digit_loop1 ()
  546. {
  547.   int key, c;
  548.  
  549.   while (1)
  550.     {
  551.       rl_message ("(arg: %d) ", arg_sign * rl_numeric_arg, 0);
  552.       key = c = rl_read_key ();
  553.  
  554.       if (keymap[c].type == ISFUNC &&
  555.       keymap[c].function == rl_universal_argument)
  556.     {
  557.       rl_numeric_arg *= 4;
  558.       continue;
  559.     }
  560.  
  561.       c = UNMETA (c);
  562.       if (numeric (c))
  563.     {
  564.       if (rl_explicit_arg)
  565.         rl_numeric_arg = (rl_numeric_arg * 10) + (c - '0');
  566.       else
  567.         rl_numeric_arg = (c - '0');
  568.       rl_explicit_arg = 1;
  569.     }
  570.       else
  571.     {
  572.       rl_clear_message ();
  573.       rl_stuff_char (key);
  574.       break;
  575.     }
  576.     }
  577. }
  578.  
  579. rl_vi_delete_to (count, key)
  580.      int count, key;
  581. {
  582.   int c;
  583.  
  584.   if (uppercase_p (key))
  585.     rl_stuff_char ('$');
  586.  
  587.   if (rl_vi_domove (key, &c))
  588.     {
  589.       ding ();
  590.       return;
  591.     }
  592.  
  593.   if ((c != '|') && (c != 'h') && rl_mark < rl_end)
  594.     rl_mark++;
  595.  
  596.   rl_kill_text (rl_point, rl_mark);
  597. }
  598.  
  599. rl_vi_change_to (count, key)
  600.      int count, key;
  601. {
  602.   int c;
  603.  
  604.   if (uppercase_p (key))
  605.     rl_stuff_char ('$');
  606.  
  607.   if (rl_vi_domove (key, &c))
  608.     {
  609.       ding ();
  610.       return;
  611.     }
  612.  
  613.   if ((c != '|') && (c != 'h') && rl_mark < rl_end)
  614.     rl_mark++;
  615.  
  616.   rl_begin_undo_group ();
  617.   vi_doing_insert = 1;
  618.   rl_kill_text (rl_point, rl_mark);
  619.   rl_vi_insertion_mode ();
  620. }
  621.  
  622. rl_vi_yank_to (count, key)
  623.      int count, key;
  624. {
  625.   int c, save = rl_point;
  626.  
  627.   if (uppercase_p (key))
  628.     rl_stuff_char ('$');
  629.  
  630.   if (rl_vi_domove (key, &c))
  631.     {
  632.       ding ();
  633.       return;
  634.     }
  635.  
  636.   rl_begin_undo_group ();
  637.   rl_kill_text (rl_point, rl_mark);
  638.   rl_end_undo_group ();
  639.   rl_do_undo ();
  640.   rl_point = save;
  641. }
  642.  
  643. rl_vi_delete (count)
  644. {
  645.   int end;
  646.  
  647.   if (rl_end == 0)
  648.     {
  649.       ding ();
  650.       return;
  651.     }
  652.  
  653.   end = rl_point + count;
  654.  
  655.   if (end >= rl_end)
  656.     end = rl_end;
  657.  
  658.   rl_kill_text (rl_point, end);
  659.   
  660.   if (rl_point > 0 && rl_point == rl_end)
  661.     rl_backward (1);
  662. }
  663.  
  664. /* Turn the current line into a comment in shell history.
  665.    A K*rn shell style function. */
  666. rl_vi_comment ()
  667. {
  668.   rl_beg_of_line ();
  669.   rl_insert_text (": ");    /* `#' doesn't work in interactive mode */
  670.   rl_redisplay ();
  671.   rl_newline (1, '\010');
  672. }
  673.  
  674. rl_vi_first_print ()
  675. {
  676.   rl_back_to_indent ();
  677. }
  678.  
  679. rl_back_to_indent (ignore1, ignore2)
  680.      int ignore1, ignore2;
  681. {
  682.   rl_beg_of_line ();
  683.   while (rl_point < rl_end && whitespace (the_line[rl_point]))
  684.     rl_point++;
  685. }
  686.  
  687. /* NOTE: it is necessary that opposite directions are inverses */
  688. #define    FTO     1        /* forward to */
  689. #define BTO    -1        /* backward to */
  690. #define FFIND     2        /* forward find */
  691. #define BFIND    -2        /* backward find */
  692.  
  693. rl_vi_char_search (count, key)
  694.      int count, key;
  695. {
  696.   static char target;
  697.   static int orig_dir, dir;
  698.   int pos;
  699.  
  700.   if (key == ';' || key == ',')
  701.     dir = (key == ';' ? orig_dir : -orig_dir);
  702.   else
  703.     {
  704.       target = rl_getc (in_stream);
  705.  
  706.       switch (key)
  707.     {
  708.     case 't':
  709.       orig_dir = dir = FTO;
  710.       break;
  711.  
  712.     case 'T':
  713.       orig_dir = dir = BTO;
  714.       break;
  715.  
  716.     case 'f':
  717.       orig_dir = dir = FFIND;
  718.       break;
  719.  
  720.     case 'F':
  721.       orig_dir = dir = BFIND;
  722.       break;
  723.     }
  724.     }
  725.  
  726.   pos = rl_point;
  727.  
  728.   if (dir < 0)
  729.     {
  730.       pos--;
  731.       do
  732.     {
  733.       if (the_line[pos] == target)
  734.         {
  735.           if (dir == BTO)
  736.         rl_point = pos + 1;
  737.           else
  738.         rl_point = pos;
  739.           return;
  740.         }
  741.     }
  742.       while (pos--);
  743.  
  744.       if (pos < 0)
  745.     {
  746.       ding ();
  747.       return;
  748.     }
  749.     }
  750.   else
  751.     {            /* dir > 0 */
  752.       pos++;
  753.       do
  754.     {
  755.       if (the_line[pos] == target)
  756.         {
  757.           if (dir == FTO)
  758.         rl_point = pos - 1;
  759.           else
  760.         rl_point = pos;
  761.           return;
  762.         }
  763.     }
  764.       while (++pos < rl_end);
  765.  
  766.       if (pos >= (rl_end - 1))
  767.     ding ();
  768.     }
  769. }
  770.  
  771. /* Match brackets */
  772. rl_vi_match ()
  773. {
  774.   int count = 1, brack, pos;
  775.  
  776.   pos = rl_point;
  777.   if ((brack = rl_vi_bracktype (the_line[rl_point])) == 0)
  778.     {
  779.       while ((brack = rl_vi_bracktype (the_line[rl_point])) == 0 &&
  780.          rl_point < rl_end - 1)
  781.     rl_forward (1);
  782.  
  783.       if (brack <= 0)
  784.     {
  785.       rl_point = pos;
  786.       ding ();
  787.       return;
  788.     }
  789.     }
  790.  
  791.   pos = rl_point;
  792.  
  793.   if (brack < 0)
  794.     {
  795.       while (count)
  796.     {
  797.       if (--pos >= 0)
  798.         {
  799.           int b = rl_vi_bracktype (the_line[pos]);
  800.           if (b == -brack)
  801.         count--;
  802.           else if (b == brack)
  803.         count++;
  804.         }
  805.       else
  806.         {
  807.           ding ();
  808.           return;
  809.         }
  810.     }
  811.     }
  812.   else
  813.     {            /* brack > 0 */
  814.       while (count)
  815.     {
  816.       if (++pos < rl_end)
  817.         {
  818.           int b = rl_vi_bracktype (the_line[pos]);
  819.           if (b == -brack)
  820.         count--;
  821.           else if (b == brack)
  822.         count++;
  823.         }
  824.       else
  825.         {
  826.           ding ();
  827.           return;
  828.         }
  829.     }
  830.     }
  831.   rl_point = pos;
  832. }
  833.  
  834. int
  835. rl_vi_bracktype (c)
  836.      int c;
  837. {
  838.   switch (c)
  839.     {
  840.     case '(': return  1;
  841.     case ')': return -1;
  842.     case '[': return  2;
  843.     case ']': return -2;
  844.     case '{': return  3;
  845.     case '}': return -3;
  846.     default:  return  0;
  847.     }
  848. }
  849.  
  850. rl_vi_change_char ()
  851. {
  852.   int c;
  853.  
  854.   c = rl_getc (in_stream);
  855.  
  856.   switch (c)
  857.     {
  858.     case '\033':
  859.     case CTRL('C'):
  860.       return;
  861.  
  862.     default:
  863.       rl_begin_undo_group ();
  864.       rl_delete (1, c);
  865.       rl_insert (1, c);
  866.       rl_end_undo_group ();
  867.       break;
  868.     }
  869. }
  870.  
  871. rl_vi_subst (count, key)
  872.      int count, key;
  873. {
  874.   rl_begin_undo_group ();
  875.   vi_doing_insert = 1;
  876.  
  877.   if (uppercase_p (key))
  878.     {
  879.       rl_beg_of_line ();
  880.       rl_kill_line (1);
  881.     }
  882.   else
  883.     rl_delete (count, key);
  884.  
  885.   rl_vi_insertion_mode ();
  886. }
  887.  
  888. rl_vi_overstrike (count, key)
  889.      int count, key;
  890. {
  891.   int i;
  892.  
  893.   if (vi_doing_insert == 0)
  894.     {
  895.       vi_doing_insert = 1;
  896.       rl_begin_undo_group ();
  897.     }
  898.  
  899.   for (i = 0; i < count; i++)
  900.     {
  901.       vi_replace_count++;
  902.       rl_begin_undo_group ();
  903.  
  904.       if (rl_point < rl_end)
  905.     {
  906.       rl_delete (1, key);
  907.       rl_insert (1, key);
  908.     }
  909.       else
  910.     rl_insert (1, key);
  911.  
  912.       rl_end_undo_group ();
  913.     }
  914. }
  915.  
  916. rl_vi_overstrike_delete (count)
  917.      int count;
  918. {
  919.   int i, s;
  920.  
  921.   for (i = 0; i < count; i++)
  922.     {
  923.       if (vi_replace_count == 0)
  924.     {
  925.       ding ();
  926.       break;
  927.     }
  928.       s = rl_point;
  929.  
  930.       if (rl_do_undo ())
  931.     vi_replace_count--;
  932.  
  933.       if (rl_point == s)
  934.     rl_backward (1);
  935.     }
  936.  
  937.   if (vi_replace_count == 0 && vi_doing_insert)
  938.     {
  939.       rl_end_undo_group ();
  940.       rl_do_undo ();
  941.       vi_doing_insert = 0;
  942.     }
  943. }
  944.  
  945. rl_vi_replace ()
  946. {
  947.   int i;
  948.  
  949.   vi_replace_count = 0;
  950.  
  951.   vi_replace_map = rl_make_bare_keymap ();
  952.  
  953.   for (i = ' '; i < 127; i++)
  954.     vi_replace_map[i].function = rl_vi_overstrike;
  955.  
  956.   vi_replace_map[RUBOUT].function = rl_vi_overstrike_delete;
  957.   vi_replace_map[ESC].function = rl_vi_movement_mode;
  958.   vi_replace_map[RETURN].function = rl_newline;
  959.   vi_replace_map[NEWLINE].function = rl_newline;
  960.   keymap = vi_replace_map;
  961. }
  962.  
  963. /*
  964.  * Try to complete the word we are standing on or the word that ends with
  965.  * the previous character. A space matches everything.
  966.  * Word delimiters are space and ;.
  967.  */
  968. rl_vi_possible_completions()
  969. {
  970.   int save_pos = rl_point;
  971.  
  972.   if (!index (" ;", the_line[rl_point]))
  973.     {
  974.       while (!index(" ;", the_line[++rl_point]))
  975.     ;
  976.     }
  977.   else if (the_line[rl_point-1] == ';')
  978.     {
  979.       ding ();
  980.       return (0);
  981.     }
  982.  
  983.   rl_possible_completions ();
  984.   rl_point = save_pos;
  985.  
  986.   return (0);
  987. }
  988.